home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / shmfs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  14.9 KB  |  713 lines

  1. /*
  2. Copyright 1992,1993 Eric R. Smith.
  3. Copyright 1993,1994 Atari Corporation.
  4. All rights reserved.
  5.  */
  6.  
  7. /* Shared memory file system */
  8.  
  9. #include "mint.h"
  10.  
  11.  
  12. static long    ARGS_ON_STACK shm_root    P_((int drv, fcookie *fc));
  13. static long    ARGS_ON_STACK shm_creat    P_((fcookie *dir, const char *name, unsigned mode,
  14.                     int attrib, fcookie *fc));
  15. static long    ARGS_ON_STACK shm_lookup    P_((fcookie *dir, const char *name, fcookie *fc));
  16. static long    ARGS_ON_STACK shm_getxattr    P_((fcookie *fc, XATTR *xattr));
  17. static long    ARGS_ON_STACK shm_chattr    P_((fcookie *fc, int attrib));
  18. static long    ARGS_ON_STACK shm_chown    P_((fcookie *fc, int uid, int gid));
  19. static long    ARGS_ON_STACK shm_chmode    P_((fcookie *fc, unsigned mode));
  20. static long    ARGS_ON_STACK shm_rmdir    P_((fcookie *dir, const char *name));
  21. static long    ARGS_ON_STACK shm_remove    P_((fcookie *dir, const char *name));
  22. static long    ARGS_ON_STACK shm_getname    P_((fcookie *root, fcookie *dir,
  23.                             char *pathname, int size));
  24. static long    ARGS_ON_STACK shm_rename    P_((fcookie *olddir, char *oldname,
  25.                     fcookie *newdir, const char *newname));
  26. static long    ARGS_ON_STACK shm_opendir    P_((DIR *dirh, int flags));
  27. static long    ARGS_ON_STACK shm_readdir    P_((DIR *dirh, char *nm, int nmlen, fcookie *));
  28. static long    ARGS_ON_STACK shm_rewinddir    P_((DIR *dirh));
  29. static long    ARGS_ON_STACK shm_closedir    P_((DIR *dirh));
  30. static long    ARGS_ON_STACK shm_pathconf    P_((fcookie *dir, int which));
  31. static long    ARGS_ON_STACK shm_dfree    P_((fcookie *dir, long *buf));
  32. static DEVDRV *    ARGS_ON_STACK shm_getdev    P_((fcookie *fc, long *devsp));
  33.  
  34. static long    ARGS_ON_STACK shm_open    P_((FILEPTR *f));
  35. static long    ARGS_ON_STACK shm_write    P_((FILEPTR *f, const char *buf, long bytes));
  36. static long    ARGS_ON_STACK shm_read    P_((FILEPTR *f, char *buf, long bytes));
  37. static long    ARGS_ON_STACK shm_lseek    P_((FILEPTR *f, long where, int whence));
  38. static long    ARGS_ON_STACK shm_ioctl    P_((FILEPTR *f, int mode, void *buf));
  39. static long    ARGS_ON_STACK shm_datime    P_((FILEPTR *f, short *time, int rwflag));
  40. static long    ARGS_ON_STACK shm_close    P_((FILEPTR *f, int pid));
  41.  
  42. /* dummy routines from biosfs.c */
  43. extern long    ARGS_ON_STACK null_select    P_((FILEPTR *f, long p, int mode));
  44. extern void    ARGS_ON_STACK null_unselect    P_((FILEPTR *f, long p, int mode));
  45.  
  46. static short shmtime, shmdate;
  47.  
  48. #define SHMNAME_MAX 15
  49.  
  50. typedef struct shmfile {
  51.     struct shmfile *next;
  52.     char filename[SHMNAME_MAX+1];
  53.     int uid, gid;
  54.     short time, date;
  55.     unsigned mode;
  56.     int inuse;
  57.     MEMREGION *reg;
  58. } SHMFILE;
  59.  
  60. SHMFILE *shmroot = 0;
  61.  
  62. DEVDRV shm_device = {
  63.     shm_open, shm_write, shm_read, shm_lseek, shm_ioctl, shm_datime,
  64.     shm_close, null_select, null_unselect
  65. };
  66.  
  67. FILESYS shm_filesys = {
  68.     (FILESYS *)0,
  69.     FS_LONGPATH,
  70.     shm_root,
  71.     shm_lookup, shm_creat, shm_getdev, shm_getxattr,
  72.     shm_chattr, shm_chown, shm_chmode,
  73.     nomkdir, shm_rmdir, shm_remove, shm_getname, shm_rename,
  74.     shm_opendir, shm_readdir, shm_rewinddir, shm_closedir,
  75.     shm_pathconf, shm_dfree,
  76.     nowritelabel, noreadlabel, nosymlink, noreadlink, nohardlink,
  77.     nofscntl, nodskchng
  78. };
  79.  
  80. long ARGS_ON_STACK 
  81. shm_root(drv, fc)
  82.     int drv;
  83.     fcookie *fc;
  84. {
  85.     if ((unsigned)drv == SHMDRV) {
  86.         fc->fs = &shm_filesys;
  87.         fc->dev = drv;
  88.         fc->index = 0L;
  89.         return 0;
  90.     }
  91.     fc->fs = 0;
  92.     return EINTRN;
  93. }
  94.  
  95. static long ARGS_ON_STACK 
  96. shm_lookup(dir, name, fc)
  97.     fcookie *dir;
  98.     const char *name;
  99.     fcookie *fc;
  100. {
  101.     SHMFILE *s;
  102.  
  103.     if (dir->index != 0) {
  104.         DEBUG(("shm_lookup: bad directory"));
  105.         return EPTHNF;
  106.     }
  107.  
  108. /* special case: an empty name in a directory means that directory */
  109. /* so does "." */
  110.     if (!*name || (name[0] == '.' && name[1] == 0)) {
  111.         *fc = *dir;
  112.         return 0;
  113.     }
  114.  
  115. /* another special case: ".." could be a mount point */
  116.     if (!strcmp(name, "..")) {
  117.         *fc = *dir;
  118.         return EMOUNT;
  119.     }
  120.  
  121.     for (s = shmroot; s; s = s->next) {
  122.         if (!stricmp(s->filename,name))
  123.             break;
  124.     }
  125.  
  126.     if (!s) {
  127.         DEBUG(("shm_lookup: name not found"));
  128.         return EFILNF;
  129.     } else {
  130.         fc->index = (long)s;
  131.         fc->fs = &shm_filesys;
  132.         fc->dev = SHMDRV;
  133.     }
  134.     return 0;
  135. }
  136.  
  137. static long ARGS_ON_STACK 
  138. shm_getxattr(fc, xattr)
  139.     fcookie *fc;
  140.     XATTR *xattr;
  141. {
  142.     SHMFILE *s;
  143.  
  144.     xattr->blksize = 1;
  145.     if (fc->index == 0) {
  146.         /* the root directory */
  147.         xattr->index = 0;
  148.         xattr->dev = xattr->rdev = SHMDRV;
  149.         xattr->nlink = 1;
  150.         xattr->uid = xattr->gid = 0;
  151.         xattr->size = xattr->nblocks = 0;
  152.         xattr->mtime = xattr->atime = xattr->ctime = shmtime;
  153.         xattr->mdate = xattr->adate = xattr->cdate = shmdate;
  154.         xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
  155.         xattr->attr = FA_DIR;
  156.         return 0;
  157.     }
  158.  
  159.     s = (SHMFILE *)fc->index;
  160.     xattr->index = (long) s;
  161.     xattr->dev = SHMDRV;
  162.     xattr->rdev = PROC_RDEV_BASE | 0;
  163.     xattr->uid = s->uid; xattr->gid = s->gid;
  164.     if (s->reg) {
  165.         xattr->size = xattr->nblocks = s->reg->len;
  166.         xattr->nlink = s->reg->links + 1;
  167.      } else {
  168.         xattr->size = xattr->nblocks = 0;
  169.         xattr->nlink = 1;
  170.     }
  171.     xattr->mtime = xattr->ctime = xattr->atime = s->time;
  172.     xattr->mdate = xattr->cdate = xattr->adate = s->date;
  173.     xattr->mode = s->mode;
  174.     xattr->attr = (s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ? 0 : 
  175.             FA_RDONLY;
  176.     return 0;
  177. }
  178.  
  179. static long ARGS_ON_STACK 
  180. shm_chattr(fc, attrib)
  181.     fcookie *fc;
  182.     int attrib;
  183. {
  184.     SHMFILE *s;
  185.  
  186.     s = (SHMFILE *)fc->index;
  187.     if (!s) return EACCDN;
  188.  
  189.     if (attrib & FA_RDONLY) {
  190.         s->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  191.     } else if ( !(s->mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ) {
  192.         s->mode |= (S_IWUSR|S_IWGRP|S_IWOTH);
  193.     }
  194.     return 0;
  195. }
  196.  
  197. static long ARGS_ON_STACK 
  198. shm_chown(fc, uid, gid)
  199.     fcookie *fc;
  200.     int uid, gid;
  201. {
  202.     SHMFILE *s;
  203.  
  204.     s = (SHMFILE *)fc->index;
  205.     if (!s)
  206.         return EACCDN;
  207.     s->uid = uid;
  208.     s->gid = gid;
  209.     return 0;
  210. }
  211.  
  212. static long ARGS_ON_STACK 
  213. shm_chmode(fc, mode)
  214.     fcookie *fc;
  215.     unsigned mode;
  216. {
  217.     SHMFILE *s;
  218.  
  219.     s = (SHMFILE *)fc->index;
  220.     if (!s)
  221.         return EINVFN;
  222.     s->mode = mode;
  223.     return 0;
  224. }
  225.  
  226. static long ARGS_ON_STACK 
  227. shm_rmdir(dir, name)
  228.     fcookie *dir;
  229.     const char *name;
  230. {
  231.     UNUSED(dir); UNUSED(name);
  232.  
  233.     return EPTHNF;
  234. }
  235.  
  236. static long ARGS_ON_STACK 
  237. shm_remove(dir, name)
  238.     fcookie *dir;
  239.     const char *name;
  240. {
  241.     SHMFILE *s, **old;
  242.  
  243.     if (dir->index != 0)
  244.         return EPTHNF;
  245.  
  246.     old = &shmroot;
  247.     for (s = shmroot; s; s = s->next) {
  248.         if (!stricmp(s->filename, name))
  249.             break;
  250.         old = &s->next;
  251.     }
  252.     if (!s)
  253.         return EFILNF;
  254.     if (s->inuse)
  255.         return EACCDN;
  256.     *old = s->next;
  257.  
  258.     s->reg->links--;
  259.     if (s->reg->links <= 0) {
  260.         free_region(s->reg);
  261.     }
  262.     kfree(s);
  263.     shmtime = timestamp;
  264.     shmdate = datestamp;
  265.     return 0;
  266. }
  267.  
  268. static long ARGS_ON_STACK 
  269. shm_getname(root, dir, pathname, size)
  270.     fcookie *root, *dir; char *pathname;
  271.     int size;
  272. {
  273.     UNUSED(root); UNUSED(dir);
  274.  
  275. /* BUG: 'size' should be used in a more meaningful way */
  276.     if (size <= 0) return ERANGE;
  277.     *pathname = 0;
  278.     return 0;
  279. }
  280.  
  281. static long ARGS_ON_STACK 
  282. shm_rename(olddir, oldname, newdir, newname)
  283.     fcookie *olddir;
  284.     char *oldname;
  285.     fcookie *newdir;
  286.     const char *newname;
  287. {
  288.     SHMFILE *s;
  289.  
  290.     if (olddir->index != 0 || newdir->index != 0)
  291.         return EPTHNF;
  292.  
  293. /* verify that "newname" doesn't exist */
  294.     for (s = shmroot; s; s = s->next)
  295.         if (!stricmp(s->filename, newname))
  296.             return EACCDN;
  297.  
  298.     for (s = shmroot; s; s = s->next)
  299.         if (!stricmp(s->filename, oldname))
  300.             break;
  301.     if (!s)
  302.         return EFILNF;
  303.  
  304.     strncpy(s->filename, newname, SHMNAME_MAX);
  305.     shmtime = timestamp;
  306.     shmdate = datestamp;
  307.     return 0;
  308. }
  309.  
  310. static long ARGS_ON_STACK 
  311. shm_opendir(dirh, flags)
  312.     DIR *dirh;
  313.     int flags;
  314. {
  315.     UNUSED(flags);
  316.  
  317.     dirh->index = 0;
  318.     return 0;
  319. }
  320.  
  321. static long ARGS_ON_STACK 
  322. shm_readdir(dirh, name, namelen, fc)
  323.     DIR *dirh;
  324.     char *name;
  325.     int namelen;
  326.     fcookie *fc;
  327. {
  328.     int i;
  329.     int giveindex = (dirh->flags == 0);
  330.     SHMFILE *s;
  331.  
  332.     s = shmroot;
  333.     i = dirh->index++;
  334.     while (i > 0 && s != 0) {
  335.         s = s->next;
  336.         --i;
  337.     }
  338.     if (!s)
  339.         return ENMFIL;
  340.  
  341.     fc->index = (long)s;
  342.     fc->fs = &shm_filesys;
  343.     fc->dev = SHMDRV;
  344.  
  345.     if (giveindex) {
  346.         namelen -= (int)sizeof(long);
  347.         if (namelen <= 0) return ERANGE;
  348.         *((long *)name) = (long)s;
  349.         name += sizeof(long);
  350.     }
  351.     if (namelen < strlen(s->filename))
  352.         return ENAMETOOLONG;
  353.     strcpy(name, s->filename);
  354.     return 0;
  355. }
  356.  
  357. static long ARGS_ON_STACK 
  358. shm_rewinddir(dirh)
  359.     DIR *dirh;
  360. {
  361.     dirh->index = 0;
  362.     return 0;
  363. }
  364.  
  365. static long ARGS_ON_STACK 
  366. shm_closedir(dirh)
  367.     DIR *dirh;
  368. {
  369.     UNUSED(dirh);
  370.     return 0;
  371. }
  372.  
  373. static long ARGS_ON_STACK 
  374. shm_pathconf(dir, which)
  375.     fcookie *dir;
  376.     int which;
  377. {
  378.     UNUSED(dir);
  379.  
  380.     switch(which) {
  381.     case -1:
  382.         return DP_MAXREQ;
  383.     case DP_IOPEN:
  384.         return UNLIMITED;    /* no internal limit on open files */
  385.     case DP_MAXLINKS:
  386.         return 1;        /* we don't have hard links */
  387.     case DP_PATHMAX:
  388.         return PATH_MAX;    /* max. path length */
  389.     case DP_NAMEMAX:
  390.         return SHMNAME_MAX;    /* max. length of individual name */
  391.     case DP_ATOMIC:
  392.         return UNLIMITED;    /* all writes are atomic */
  393.     case DP_TRUNC:
  394.         return DP_AUTOTRUNC;    /* file names are truncated */
  395.     case DP_CASE:
  396.         return DP_CASEINSENS;    /* case preserved, but ignored */
  397.     case DP_MODEATTR:
  398.         return (0777L << 8)|
  399.                 DP_FT_DIR|DP_FT_MEM;
  400.     case DP_XATTRFIELDS:
  401.         return DP_INDEX|DP_DEV|DP_NLINK|DP_UID|DP_GID|DP_BLKSIZE|DP_SIZE|
  402.                 DP_NBLOCKS|DP_MTIME;
  403.     default:
  404.         return EINVFN;
  405.     }
  406. }
  407.  
  408. static long ARGS_ON_STACK 
  409. shm_dfree(dir, buf)
  410.     fcookie *dir;
  411.     long *buf;
  412. {
  413.     long size;
  414. /* "sector" size is the size of the smallest amount of memory that can be
  415.    allocated. see mem.h for the definition of ROUND
  416.  */
  417.     long secsiz = ROUND(1);
  418.  
  419.     UNUSED(dir);
  420.  
  421.     size = tot_rsize(core, 0) + tot_rsize(alt, 0);
  422.     *buf++ = size/secsiz;            /* number of free clusters */
  423.     size = tot_rsize(core, 1) + tot_rsize(alt, 1);
  424.     *buf++ = size/secsiz;            /* total number of clusters */
  425.     *buf++ = secsiz;            /* sector size (bytes) */
  426.     *buf = 1;                /* cluster size (in sectors) */
  427.     return 0;
  428. }
  429.  
  430. static DEVDRV * ARGS_ON_STACK 
  431. shm_getdev(fc, devsp)
  432.     fcookie *fc;
  433.     long *devsp;
  434. {
  435.     SHMFILE *s;
  436.  
  437.     s = (SHMFILE *)fc->index;
  438.  
  439.     *devsp = (long)s;
  440.     return &shm_device;
  441. }
  442.  
  443. /*
  444.  * create a shared memory region
  445.  */
  446.  
  447. static long ARGS_ON_STACK 
  448. shm_creat(dir, name, mode, attrib, fc)
  449.     fcookie *dir;
  450.     const char *name;
  451.     unsigned mode;
  452.     int attrib;
  453.     fcookie *fc;
  454. {
  455.     SHMFILE *s;
  456.  
  457.     UNUSED(attrib);
  458. /*
  459.  * see if the name already exists
  460.  */
  461.     for (s = shmroot; s; s = s->next) {
  462.         if (!stricmp(s->filename, name)) {
  463.             DEBUG(("shm_creat: file exists"));
  464.             return EACCDN;
  465.         }
  466.     }
  467.  
  468.     s = (SHMFILE *)kmalloc(SIZEOF(SHMFILE));
  469.     if (!s)
  470.         return ENSMEM;
  471.  
  472.     s->inuse = 0;
  473.     strncpy(s->filename, name, SHMNAME_MAX);
  474.     s->filename[SHMNAME_MAX] = 0;
  475.     s->uid = curproc->euid;
  476.     s->gid = curproc->egid;
  477.     s->mode = mode;
  478.     s->next = shmroot;
  479.     s->reg = 0;
  480.     s->time = shmtime = timestamp;
  481.     s->date = shmdate = datestamp;
  482.     shmroot = s;
  483.  
  484.     fc->fs = &shm_filesys;
  485.     fc->index = (long)s;
  486.     fc->dev = dir->dev;
  487.  
  488.     return 0;
  489. }
  490.  
  491. /*
  492.  * Shared memory device driver
  493.  */
  494.  
  495. /*
  496.  * BUG: file locking and the O_SHMODE restrictions are not implemented
  497.  * for shared memory
  498.  */
  499.  
  500. static long ARGS_ON_STACK 
  501. shm_open(f)
  502.     FILEPTR *f;
  503. {
  504.     SHMFILE *s;
  505.  
  506.     s = (SHMFILE *)f->devinfo;
  507.     s->inuse++;
  508.     return 0;
  509. }
  510.  
  511. static long ARGS_ON_STACK 
  512. shm_write(f, buf, nbytes)
  513.     FILEPTR *f; const char *buf; long nbytes;
  514. {
  515.     SHMFILE *s;
  516.     char *where;
  517.     long bytes_written = 0;
  518.  
  519.     s = (SHMFILE *)f->devinfo;
  520.     if (!s->reg)
  521.         return 0;
  522.  
  523.     if (nbytes + f->pos > s->reg->len)
  524.         nbytes = s->reg->len - f->pos;
  525.  
  526.     where = (char *)s->reg->loc + f->pos;
  527.  
  528. /* BUG: memory read/writes should check for valid addresses */
  529.  
  530. TRACE(("shm_write: %ld bytes to %lx", nbytes, where));
  531.  
  532.     while (nbytes-- > 0) {
  533.         *where++ = *buf++;
  534.         bytes_written++;
  535.     }
  536.     f->pos += bytes_written;
  537.     s->time = timestamp;
  538.     s->date = datestamp;
  539.     return bytes_written;
  540. }
  541.  
  542. static long ARGS_ON_STACK 
  543. shm_read(f, buf, nbytes)
  544.     FILEPTR *f; char *buf; long nbytes;
  545. {
  546.     SHMFILE *s;
  547.     char *where;
  548.     long bytes_read = 0;
  549.  
  550.     s = (SHMFILE *)f->devinfo;
  551.     if (!(s->reg))
  552.         return 0;
  553.  
  554.     if (nbytes + f->pos > s->reg->len)
  555.         nbytes = s->reg->len - f->pos;
  556.  
  557.     where = (char *)s->reg->loc + f->pos;
  558.  
  559. TRACE(("shm_read: %ld bytes from %lx", nbytes, where));
  560.  
  561.     while (nbytes-- > 0) {
  562.         *buf++ = *where++;
  563.         bytes_read++;
  564.     }
  565.     f->pos += bytes_read;
  566.     return bytes_read;
  567. }
  568.  
  569. /*
  570.  * shm_ioctl: currently, the only IOCTL's available are:
  571.  * SHMSETBLK:  set the address of the shared memory file. This
  572.  *             call may only be made once per region, and then only
  573.  *           if the region is open for writing.
  574.  * SHMGETBLK:  get the address of the shared memory region. This
  575.  *             call fails (returns 0) if SHMSETBLK has not been
  576.  *             called yet for this shared memory file.
  577.  */
  578.  
  579. static long ARGS_ON_STACK 
  580. shm_ioctl(f, mode, buf)
  581.     FILEPTR *f; int mode; void *buf;
  582. {
  583.     SHMFILE *s;
  584.     MEMREGION *m;
  585.     int i;
  586.     long r;
  587.  
  588.     s = (SHMFILE *)f->devinfo;
  589.     switch(mode) {
  590.     case SHMSETBLK:
  591.         if (s->reg) {
  592.             DEBUG(("Fcntl: SHMSETBLK already performed for %s",
  593.                 s->filename));
  594.             return ERANGE;
  595.         }
  596.         if ((f->flags & O_RWMODE) == O_RDONLY) {
  597.             DEBUG(("Fcntl: SHMSETBLK: %s was opened read-only",
  598.                 s->filename));
  599.             return EACCDN;
  600.         }
  601.     /* find the memory region to be attached */
  602.         m = 0;
  603.         for (i = curproc->num_reg - 1; i >= 0; i--) {
  604.             if (curproc->addr[i] == (virtaddr)buf) {
  605.                 m = curproc->mem[i];
  606.                 break;
  607.             }
  608.         }
  609.         if (!m || !buf) {
  610.             DEBUG(("Fcntl: SHMSETBLK: bad address %lx", buf));
  611.             return EIMBA;
  612.         }
  613.         m->links++;
  614.         s->reg = m;
  615.         return 0;
  616.     case SHMGETBLK:
  617.         if ((m = s->reg) == 0) {
  618.             DEBUG(("Fcntl: no address for SHMGETBLK"));
  619.             return 0;
  620.         }
  621.     /* check for memory limits */
  622.         if (curproc->maxmem) {
  623.             if (m->len > curproc->maxmem - memused(curproc)) {
  624.                 DEBUG(("Fcntl: SHMGETBLK would violate memory limits"));
  625.                 return 0;
  626.             }
  627.         }
  628.         return (long)attach_region(curproc, m);
  629.     case FIONREAD:
  630.     case FIONWRITE:
  631.         if (s->reg == 0) {
  632.             r = 0;
  633.         } else {
  634.             r = s->reg->len - f->pos;
  635.             if (r < 0) r = 0;
  636.         }
  637.         *((long *)buf) = r;
  638.         return 0;
  639.     default:
  640.         DEBUG(("shmfs: bad Fcntl command"));
  641.     }
  642.     return EINVFN;
  643. }
  644.  
  645. static long ARGS_ON_STACK 
  646. shm_lseek(f, where, whence)
  647.     FILEPTR *f; long where; int whence;
  648. {
  649.     long newpos, maxpos;
  650.     SHMFILE *s;
  651.  
  652.     s = (SHMFILE *)f->devinfo;
  653.  
  654.     if (s->reg)
  655.         maxpos = s->reg->len;
  656.     else
  657.         maxpos = 0;
  658.  
  659.     switch(whence) {
  660.     case 0:
  661.         newpos = where;
  662.         break;
  663.     case 1:
  664.         newpos = f->pos + where;
  665.         break;
  666.     case 2:
  667.         newpos = maxpos + where;
  668.         break;
  669.     default:
  670.         return EINVFN;
  671.     }
  672.  
  673.     if (newpos < 0 || newpos > maxpos)
  674.         return ERANGE;
  675.  
  676.     f->pos = newpos;
  677.     return newpos;
  678. }
  679.  
  680. static long ARGS_ON_STACK 
  681. shm_datime(f, timeptr, rwflag)
  682.     FILEPTR *f;
  683.     short *timeptr;
  684.     int rwflag;
  685. {
  686.     SHMFILE *s;
  687.  
  688.     s = (SHMFILE *)f->devinfo;
  689.     if (rwflag) {
  690.         s->time = *timeptr++;
  691.         s->date = *timeptr;
  692.     } else {
  693.         *timeptr++ = s->time;
  694.         *timeptr = s->date;
  695.     }
  696.     return 0;
  697. }
  698.  
  699. static long ARGS_ON_STACK 
  700. shm_close(f, pid)
  701.     FILEPTR *f;
  702.     int pid;
  703. {
  704.     SHMFILE *s;
  705.  
  706.     UNUSED(pid);
  707.     if (f->links <= 0) {
  708.         s = (SHMFILE *)f->devinfo;
  709.         s->inuse--;
  710.     }
  711.     return 0;
  712. }
  713.